"""
    数据清洗模块： 可以简单的清洗，主要通过loop_node这个函数
    注意：
        1. 获取到的节点有2种情况，元素节点和文本节点
        2. 节点深度为2的情况下，获取到的字典的值（list类型），它的长度一般为1，但不一定
"""

from lxml import etree
import re

# etree 节点类型
etree_unicode_type = etree._ElementUnicodeResult
etree_element_type = etree._Element

# 解析 node 节点深度
node_depth = []

def hello(): 
    print("Hello parse.py")

def getUrlTitle(spider_txt):
    """ 获取网页标题 """
    data = re.findall('<title.*>(.*?)</title>', spider_txt, re.S)
    if len(data) >= 1:
        return data[0].strip()


def remove_blank(str_text):
    """ 过滤标点符号等特殊字符 """

    # 规则1: 去除所有空格
    temp_arr = str_text.strip().split()
    return "".join(temp_arr)

    # 规则2: 去除所有空格、标点符号
    # return re.sub('\W+', '', str_text).replace("_", '')


def add_to_node_dict(node_depth_last,node,node_dict):
    """ 
        添加进节点字典 
        :node_depth_last 节点深度最后1个节点
        :node 要添加的节点
        :node_dict 节点字典
    """
    node_dict_key = str(node_depth_last)
    if node_dict_key not in node_dict:
        node_dict[node_dict_key] = []
    node_dict[node_dict_key].append(node)
    return node_dict


def update_node_dict(new_node_dict,old_node_dict):
    """
        更新节点字典:
        :new_node_dict 新添加到 node_dict 的一些字典
        :old_node_dict 原来已经保存的节点字典
    """
    for k,v in new_node_dict.items():
        if k not in old_node_dict:
            old_node_dict[k] = []
        old_node_dict[k].extend(v)
    return old_node_dict


def loop_node(parent_node, filter_tags = [], depth = 1):
    """ 
        循环当前元素节点的下面所有节点,
        1. 可以指定过滤掉哪些不要的标签（元素节点）filter_tags
        2. 可以指定深度，验证过节点深度为2，大于2不确定 depth
    """
    child_nodes = parent_node.xpath("node()")
    # unicode节点 元素节点
    nodes = []
    # 保存上下节点关系的字典
    node_dict = {}

    # 保持节点深度
    if len(node_depth) < depth: 
        node_depth.append(parent_node)


    if len(child_nodes) == 0:
        return [child_nodes, node_dict]

    # 排除特殊情况 <div>xx</div> 
    # 或者当且只有1个节点时其类型为 etree_unicode_type
    if len(child_nodes) == 1 and isinstance(child_nodes[0], etree_unicode_type) == True:
        nodes.append(parent_node)
        # 将 <xxx>....</xxx> 类似的元素添加到各自的节点字典中
        node_dict = add_to_node_dict(node_depth[-1], parent_node, node_dict)
        return [nodes, node_dict]
    
    for node in child_nodes:
        if isinstance(node, etree_unicode_type) == True: 
            # 文本节点过滤掉空字符【换行等】
            node_unicode_text = remove_blank(node)
            if node_unicode_text != "":
                nodes.append(node_unicode_text)
                # 将文本节点存放入对应的节点深度
                node_dict = add_to_node_dict(node_depth[-1], node_unicode_text, node_dict)
                # node_dict = update_node_dict(temp_node_dict, node_dict)

                # print("parent_node:", parent_node)
                # print("node_depth:", node_depth)
                # print(node_unicode_text)
                # print()
            
        else:
            # 根据过滤条件,过滤一些节点
            if node.tag in filter_tags:
                continue
            # 元素节点,前面排除: 0个、1个且是文本节点
            tmp_nodes,temp_node_dict = loop_node(node, filter_tags, depth)
           
            if node == node_depth[-1]:
                # 从节点深度弹出最后一个元素, node 节点已到叶子节点
                # 这里只校验了节点深度： 最高小于等于2
                node_depth.pop()

            # print("temp_node_dict:" ,temp_node_dict)
            # print("前node_dict:" ,node_dict)
            # for k,v in temp_node_dict.items():
            #     if k not in node_dict:
            #         node_dict[k] = []
            #     node_dict[k].extend(v)
            # print("后node_dict:" ,node_dict)
            # print()
            node_dict = update_node_dict(temp_node_dict, node_dict)

            # if node_depth[-1] == node:
            #     print("node:", node, ",nodes:", nodes)
            
            # temp_node_dict = add_to_node_dict(node_depth[-1], node, temp_node_dict)

            # print("node:", node,",tmp_node_dict:", temp_node_dict,",parent_node:", parent_node)
            # for k,v in node_dict:
            #     print("key:", k, ",value:", v)

            # print("node_depth:", node_depth)
            # node_dict_key = str(node_depth[-1])
            # if node_dict_key not in node_dict:
            #     # 当节点字典中没有对应 key,初始化为 []
            #     node_dict[node_dict_key] = []
            # node_dict[node_dict_key].append(node)
            

    return [nodes, node_dict]


class Parse:
    def __init__(self,spider_txt):
        """
            初始化 Parse 类
            :param spider_txt 爬取的网页文本
        """
        
        # 从字符串常量分析HTML文档。返回根nood <Element html at 0x1f9c5e40680>
        self.rootEle = etree.HTML(spider_txt)


    def getElements(self, x_path):
        """
            根据网页的 xpath 路径获取网页元素 
            :param x_path 从浏览器复制路径
            :return 类似[<Element a at 0x24da5f90ec0>]
        """
        return self.rootEle.xpath(x_path)

    def getText(self, element):
        """
            通过获取到的元素,获取元素中的文本
            :param element etree 转换的元素对象
        """
        # element.xpath("text()") ==> []
        return element.text

    def getLink(self, element):
        """
            通过获取到的元素,获取元素中的链接
            :param element etree转换的元素对象
        """
        # 获取元素所有属性: element.attrib
        # 如果没有 href 属性会报错
        return element.attrib["href"]

